package com.wei.web.middleware.httpfilter.registrar;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.wei.web.middleware.httpfilter.enums.ErrorEnum;
import com.wei.web.middleware.httpfilter.exceptions.FASException;
import com.wei.web.middleware.httpfilter.registrar.filter.*;
import com.wei.web.middleware.httpfilter.registrar.model.RegisterContext;
import com.wei.web.middleware.httpfilter.registrar.model.FilterConfigDTO;
import com.wei.web.middleware.httpfilter.registrar.security.SecurityAuthRegistrar;
import com.wei.web.middleware.httpfilter.utils.FileUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotationMetadata;

import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class WebFilterRegistrarManager implements ImportBeanDefinitionRegistrar {

    public static final String RESOURCE_LOCATION = "filters/filters_config.json";

    public static ConcurrentHashMap<String, IRegistrar> registrarMap = new ConcurrentHashMap<>();

    static {
        registerFilterRegistrar(new CorsFilterRegistrar());
        registerFilterRegistrar(new CustomFilterBeanRegistrar());
        registerFilterRegistrar(new CustomFilterClassRegistrar());
        registerFilterRegistrar(new CustomFilterFactoryBeanRegistrar());
        registerFilterRegistrar(new HttpContextFilterRegistrar());
        registerFilterRegistrar(new ServerAuthFilterRegistrar());
        registerFilterRegistrar(new TraceFilterRegistrar());
        registerFilterRegistrar(new SecurityAuthRegistrar());
    }


    @SneakyThrows
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        try {
            List<FilterConfigDTO> filterConfigDTOList = getFilterConfig();
            doRegisterFilters(filterConfigDTOList, registry);
        } catch (IOException e) {
            throw e;
        }
    }

    private void doRegisterFilters(List<FilterConfigDTO> filterConfigDTOList, BeanDefinitionRegistry registry) {
        RegisterContext registerContext = RegisterContext.builder()
                .filterOrder(Ordered.HIGHEST_PRECEDENCE)
                .build();

        for(FilterConfigDTO filterConfigDTO : filterConfigDTOList) {
            IRegistrar registrar = registrarMap.get(filterConfigDTO.getType());
            if (registrar == null) {
                throw new FASException(ErrorEnum.INVALID_FILTER_TYPE);
            }
            registrar.registrar(filterConfigDTO, registry, registerContext);
            registerContext.setFilterOrder(registerContext.getFilterOrder()+1);
        }
    }

    private List<FilterConfigDTO> getFilterConfig() throws IOException {
        List<FilterConfigDTO> filterConfigDTOList = null;

        ClassLoader classLoader = WebFilterRegistrarManager.class.getClassLoader();
        String configStr = FileUtil.getContent(RESOURCE_LOCATION, classLoader);

        filterConfigDTOList = JSONObject.parseObject(configStr, new TypeReference<>() {});

        return filterConfigDTOList;
    }

    private static void registerFilterRegistrar(IRegistrar registrar) {
        registrarMap.put(registrar.getType(), registrar);
    }

}
